﻿using System;
using System.Linq;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;
using System.ComponentModel;

namespace OpenLightGroup.Common.Behaviors
{
    /// <summary>
    /// Adds RadioButtonList or CheckBoxList like behavior to a ListBox by keep the SelectedItems of the ListBox in sync with 
    /// which ToggleButton(s) are selected.
    /// </summary>
    [Description("Adds functionality to a ListBox to synchronize the selectedItem(s) with which ToggleButton(s) are checked.")]
    public class ToggleButtonListBoxBehavior : Behavior<ListBox>
    {

        private bool itemEventHandlersWired = false;

        /// <summary>
        /// Wires up event handlers to the ListBox's LayoutUpdated and SelectionChanged events.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            // Insert code that you would want run when the Behavior is attached to an object.
            this.AssociatedObject.LayoutUpdated += new EventHandler(AssociatedObject_LayoutUpdated);

            this.AssociatedObject.SelectionChanged += new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);

        }


        /// <summary>
        /// Removes event handlers from the ListBox and the toggle button included in each item's template.
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            this.AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;

            var listBoxItems = this.AssociatedObject.ChildrenOfType<ListBoxItem>();

            foreach (ListBoxItem item in listBoxItems)
            {

                var b = item.ChildOfType<ToggleButton>();

                if (b != null)
                {
                    b.Checked -= ToggleButton_CheckChanged;
                    b.Unchecked -= ToggleButton_CheckChanged;
                }

            }

        }


        private void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
        {
            if (this.itemEventHandlersWired == false)
            {
                var listBoxItems = this.AssociatedObject.ChildrenOfType<ListBoxItem>();

                if (listBoxItems.Count() > 0 )
                {
                   
                    foreach (ListBoxItem item in listBoxItems)
                    {
                        var b = item.ChildOfType<ToggleButton>();

                        if (b != null)
                        {
                            b.IsChecked = item.IsSelected;
                            b.Checked += new RoutedEventHandler(ToggleButton_CheckChanged);
                            b.Unchecked += new RoutedEventHandler(ToggleButton_CheckChanged);
                        }

                    }

                    this.itemEventHandlersWired = true;
                    this.AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
                }
            }
        }

        private void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            this.ToggleItemsIsChecked(e.AddedItems, true);

            this.ToggleItemsIsChecked(e.RemovedItems, false);

        }

        private void ToggleButton_CheckChanged(object sender, RoutedEventArgs e)
        {

            ToggleButton b = sender as ToggleButton;

            var isChecked = (b != null && b.IsChecked.HasValue) ? b.IsChecked.Value : false;

            b.ParentOfType<ListBoxItem>().IsSelected = isChecked;

        }

        private void ToggleItemsIsChecked(IList items, bool isChecked)
        {
            foreach (var currentItem in items)
            {
                var item = this.AssociatedObject.ItemContainerGenerator.ContainerFromItem(currentItem) as ListBoxItem;

                ToggleButton b = item.ChildOfType<ToggleButton>();

                if (b != null)
                    b.IsChecked = isChecked;

            }
        }

    }
}